package io.github.jsp.scheduler;

import io.github.jsp.executor.JobExecutor;
import io.github.jsp.lock.JobTriggerLock;
import io.github.jsp.model.JobInfo;
import io.github.jsp.model.JobLog;
import io.github.jsp.service.JobInfoService;
import io.github.jsp.service.JobLogService;
import io.github.jsp.util.ServerIdUtil;
import org.quartz.CronExpression;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.sql.Timestamp;
import java.text.ParseException;
import java.util.Date;

@Service
public class JobTriggerService {
    
    private static final Logger logger = LoggerFactory.getLogger(JobTriggerService.class);
    
    @Autowired
    private JobTriggerLock jobTriggerLock;
    
    @Autowired
    private JobInfoService jobInfoService;
    
    @Autowired
    private JobLogService jobLogService;
    
    @Autowired
    private JobExecutor jobExecutor;
    
    private static final long TRIGGER_LOCK_TIMEOUT = 60000;
    
    public void trigger(JobInfo jobInfo) {
        if (jobInfo == null || jobInfo.getId() == null) {
            logger.warn("Invalid job info for triggering");
            return;
        }
        
        String nodeId = ServerIdUtil.getNodeId();
        
        if (!jobTriggerLock.tryLockJob(jobInfo.getId(), nodeId, TRIGGER_LOCK_TIMEOUT)) {
            logger.debug("Failed to acquire trigger lock for job: {} on node: {}", 
                jobInfo.getId(), nodeId);
            return;
        }
        
        try {
            JobLog jobLog = createJobLog(jobInfo);
            
            jobInfoService.updateTriggerTime(jobInfo.getId(), System.currentTimeMillis());
            
            jobExecutor.execute(jobInfo, jobLog);
            
            logger.debug("Triggered job: {} on node: {}", jobInfo.getId(), nodeId);
            
        } catch (Exception e) {
            logger.error("Error triggering job: {} on node: {}", jobInfo.getId(), nodeId, e);
        } finally {
            jobTriggerLock.unlockJob(jobInfo.getId(), nodeId);
        }
    }
    
    private JobLog createJobLog(JobInfo jobInfo) {
        JobLog jobLog = new JobLog();
        jobLog.setJobGroup(jobInfo.getJobGroup());
        jobLog.setJobId(jobInfo.getId());
        jobLog.setExecutorAddress(ServerIdUtil.getServerAddress());
        jobLog.setExecutorHandler(jobInfo.getJobClassName());
        jobLog.setExecutorParam(jobInfo.getJobParam());
        jobLog.setExecutorFailRetryCount(jobInfo.getExecutorFailRetryCount());
        jobLog.setTriggerTime(new Timestamp(System.currentTimeMillis()));
        jobLog.setTriggerCode(200);
        jobLog.setTriggerMsg("Trigger success");
        
        return jobLog;
    }
    
    public Long calculateNextTriggerTime(String cronExpr) {
        try {
            CronExpression cronExpression = new CronExpression(cronExpr);
            Date nextFireTime = cronExpression.getNextValidTimeAfter(new Date());
            return nextFireTime != null ? nextFireTime.getTime() : null;
        } catch (ParseException e) {
            logger.error("Invalid cron expression: {}", cronExpr, e);
            return null;
        }
    }
}